import io
import os
import sys

sys.path.insert(0, os.path.abspath("../.."))

import asyncio
import json
import logging
import tempfile
from litellm._uuid import uuid

import json
from datetime import datetime, timedelta, timezone
from datetime import datetime

import pytest

import litellm
from litellm import completion
from litellm._logging import verbose_logger
from litellm.integrations.gcs_bucket.gcs_bucket import (
    GCSBucketLogger,
    StandardLoggingPayload,
)
from litellm.types.utils import StandardCallbackDynamicParams


# This is the response payload that GCS would return.
mock_response_data = {
    "id": "chatcmpl-9870a859d6df402795f75dc5fca5b2e0",
    "trace_id": None,
    "call_type": "acompletion",
    "cache_hit": None,
    "stream": True,
    "status": "success",
    "custom_llm_provider": "openai",
    "saved_cache_cost": 0.0,
    "startTime": 1739235379.683053,
    "endTime": 1739235379.84533,
    "completionStartTime": 1739235379.84533,
    "response_time": 0.1622769832611084,
    "model": "my-fake-model",
    "metadata": {
        "user_api_key_hash": "88dc28d0f030c55ed4ab77ed8faf098196cb1c05df778539800c9f1243fe6b4b",
        "user_api_key_alias": None,
        "user_api_key_team_id": None,
        "user_api_key_org_id": None,
        "user_api_key_user_id": "default_user_id",
        "user_api_key_team_alias": None,
        "spend_logs_metadata": None,
        "requester_ip_address": "127.0.0.1",
        "requester_metadata": {},
        "user_api_key_end_user_id": None,
        "prompt_management_metadata": None,
    },
    "cache_key": None,
    "response_cost": 3.7500000000000003e-05,
    "total_tokens": 21,
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "request_tags": [],
    "end_user": "",
    "api_base": "https://exampleopenaiendpoint-production.up.railway.app",
    "model_group": "fake-openai-endpoint",
    "model_id": "b68d56d76b0c24ac9462ab69541e90886342508212210116e300441155f37865",
    "requester_ip_address": "127.0.0.1",
    "messages": [
        {"role": "user", "content": [{"type": "text", "text": "very gm to u"}]}
    ],
    "response": {
        "id": "chatcmpl-9870a859d6df402795f75dc5fca5b2e0",
        "created": 1677652288,
        "model": "gpt-3.5-turbo-0301",
        "object": "chat.completion",
        "system_fingerprint": "fp_44709d6fcb",
        "choices": [
            {
                "finish_reason": "stop",
                "index": 0,
                "message": {
                    "content": "\n\nHello there, how may I assist you today?",
                    "role": "assistant",
                    "tool_calls": None,
                    "function_call": None,
                    "refusal": None,
                },
            }
        ],
        "usage": {
            "completion_tokens": 12,
            "prompt_tokens": 9,
            "total_tokens": 21,
            "completion_tokens_details": None,
            "prompt_tokens_details": None,
        },
        "service_tier": None,
    },
    "model_parameters": {"stream": False, "max_retries": 0, "extra_body": {}},
    "hidden_params": {
        "model_id": "b68d56d76b0c24ac9462ab69541e90886342508212210116e300441155f37865",
        "cache_key": None,
        "api_base": "https://exampleopenaiendpoint-production.up.railway.app/",
        "response_cost": 3.7500000000000003e-05,
        "additional_headers": {},
        "litellm_overhead_time_ms": 2.126,
    },
    "model_map_information": {
        "model_map_key": "gpt-3.5-turbo-0301",
        "model_map_value": {},
    },
    "error_str": None,
    "error_information": {"error_code": "", "error_class": "", "llm_provider": ""},
    "response_cost_failure_debug_info": None,
    "guardrail_information": None,
}


@pytest.mark.asyncio
async def test_get_payload_current_day():
    """
    Verify that the payload is returned when it is found on the current day.
    """
    gcs_logger = GCSBucketLogger()
    # Use January 1, 2024 as the current day
    start_time = datetime(2024, 1, 1, tzinfo=timezone.utc)
    request_id = mock_response_data["id"]

    async def fake_download(object_name: str, **kwargs) -> bytes | None:
        if "2024-01-01" in object_name:
            return json.dumps(mock_response_data).encode("utf-8")
        return None

    gcs_logger.download_gcs_object = fake_download

    payload = await gcs_logger.get_request_response_payload(
        request_id, start_time, None
    )
    assert payload is not None
    assert payload["id"] == request_id


@pytest.mark.asyncio
async def test_get_payload_next_day():
    """
    Verify that if the payload is not found on the current day,
    but is available on the next day, it is returned.
    """
    gcs_logger = GCSBucketLogger()
    start_time = datetime(2024, 1, 1, tzinfo=timezone.utc)
    request_id = mock_response_data["id"]

    async def fake_download(object_name: str, **kwargs) -> bytes | None:
        if "2024-01-02" in object_name:
            return json.dumps(mock_response_data).encode("utf-8")
        return None

    gcs_logger.download_gcs_object = fake_download

    payload = await gcs_logger.get_request_response_payload(
        request_id, start_time, None
    )
    assert payload is not None
    assert payload["id"] == request_id


@pytest.mark.asyncio
async def test_get_payload_previous_day():
    """
    Verify that if the payload is not found on the current or next day,
    but is available on the previous day, it is returned.
    """
    gcs_logger = GCSBucketLogger()
    start_time = datetime(2024, 1, 1, tzinfo=timezone.utc)
    request_id = mock_response_data["id"]

    async def fake_download(object_name: str, **kwargs) -> bytes | None:
        if "2023-12-31" in object_name:
            return json.dumps(mock_response_data).encode("utf-8")
        return None

    gcs_logger.download_gcs_object = fake_download

    payload = await gcs_logger.get_request_response_payload(
        request_id, start_time, None
    )
    assert payload is not None
    assert payload["id"] == request_id


@pytest.mark.asyncio
async def test_get_payload_not_found():
    """
    Verify that if none of the three days contain the payload, None is returned.
    """
    gcs_logger = GCSBucketLogger()
    start_time = datetime(2024, 1, 1, tzinfo=timezone.utc)
    request_id = mock_response_data["id"]

    async def fake_download(object_name: str, **kwargs) -> bytes | None:
        return None

    gcs_logger.download_gcs_object = fake_download

    payload = await gcs_logger.get_request_response_payload(
        request_id, start_time, None
    )
    assert payload is None
